/*
* Copyright (c) Microsoft Corporation.  All Rights Reserved.
*
* Shim called by the target function, which dispatches to the actual mock function.
*/
#pragma once
#include "Mock10.h"
#include "DetourMethod.h"
#include "DetourThunk.h"
#include "ParameterTypes.h"

#pragma push_macro("Assert")
#undef Assert

extern "C" void* _ReturnAddress(void);
#pragma intrinsic(_ReturnAddress)

namespace Mock10 { namespace Private
{
    class Detour;

    template <typename TPrototype, typename TDetourFunction>
    struct DetourShim;

    #define DETOUR_SHIM_NAMED_ARGS_0 
    #define DETOUR_SHIM_NAMED_ARGS_1 typename T1 p1
    #define DETOUR_SHIM_NAMED_ARGS_2 typename T1 p1, typename T2 p2
    #define DETOUR_SHIM_NAMED_ARGS_3 typename T1 p1, typename T2 p2, typename T3 p3
    #define DETOUR_SHIM_NAMED_ARGS_4 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4
    #define DETOUR_SHIM_NAMED_ARGS_5 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5
    #define DETOUR_SHIM_NAMED_ARGS_6 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6
    #define DETOUR_SHIM_NAMED_ARGS_7 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7
    #define DETOUR_SHIM_NAMED_ARGS_8 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8
    #define DETOUR_SHIM_NAMED_ARGS_9 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9
    #define DETOUR_SHIM_NAMED_ARGS_10 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10
    #define DETOUR_SHIM_NAMED_ARGS_11 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11
    #define DETOUR_SHIM_NAMED_ARGS_12 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12
    #define DETOUR_SHIM_NAMED_ARGS_13 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13
    #define DETOUR_SHIM_NAMED_ARGS_14 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14
    #define DETOUR_SHIM_NAMED_ARGS_15 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15
    #define DETOUR_SHIM_NAMED_ARGS_16 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15, typename T16 p16
    #define DETOUR_SHIM_NAMED_ARGS_17 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15, typename T16 p16, typename T17 p17
    #define DETOUR_SHIM_NAMED_ARGS_18 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15, typename T16 p16, typename T17 p17, typename T18 p18
    #define DETOUR_SHIM_NAMED_ARGS_19 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15, typename T16 p16, typename T17 p17, typename T18 p18, typename T19 p19
    #define DETOUR_SHIM_NAMED_ARGS_20 typename T1 p1, typename T2 p2, typename T3 p3, typename T4 p4, typename T5 p5, typename T6 p6, typename T7 p7, typename T8 p8, typename T9 p9, typename T10 p10, typename T11 p11, typename T12 p12, typename T13 p13, typename T14 p14, typename T15 p15, typename T16 p16, typename T17 p17, typename T18 p18, typename T19 p19, typename T20 p20

    #define SHIM_PARAMETER_TYPES_TEMPLATE_0 template <typename TR, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_1 template <typename TR, typename T1, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_2 template <typename TR, typename T1, typename T2, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_3 template <typename TR, typename T1, typename T2, typename T3, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_4 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_5 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_6 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_7 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_8 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_9 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_10 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_11 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_12 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_13 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_14 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_15 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_16 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_17 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_18 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_19 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename T19, typename TDetourFunction>
    #define SHIM_PARAMETER_TYPES_TEMPLATE_20 template <typename TR, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename T19, typename T20, typename TDetourFunction>
    
    #define DETOUR_SHIM(PARAMCOUNT, CC) \
    BUILD_VARIABLE_NAME(SHIM_PARAMETER_TYPES_TEMPLATE_, PARAMCOUNT) \
    struct DetourShim<TR CC (BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)), TDetourFunction> \
    { \
        __declspec(noinline) static TR CC Shim(BUILD_VARIABLE_NAME(DETOUR_SHIM_NAMED_ARGS_, PARAMCOUNT)) \
        { \
            /* Get the Detour instance from Tls */ \
            Detour* pDetour = NULL; \
            HRESULT hr = DetourThunk::GetDetourTlsValue(reinterpret_cast<intptr_t&>(pDetour)); \
            DBG_UNREFERENCED_LOCAL_VARIABLE(hr); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the Detour* pointer from Tls"); \
            WEX_ASSERT(pDetour, L"Failed to retrieve a valid Detour* pointer from Tls"); \
            \
            /* Get the Target function pointer from Tls */ \
            typedef TR (CC* TargetFunction)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)); \
            TargetFunction pTarget = NULL; \
            hr = DetourThunk::GetTargetTlsValue(reinterpret_cast<intptr_t&>(pTarget)); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the target function pointer from Tls"); \
            WEX_ASSERT(pTarget, L"Failed to retrieve a valid target function pointer from Tls"); \
            \
            void* pReturnAddress = NULL; \
            hr = DetourThunk::GetReturnAddressTlsValue(reinterpret_cast<intptr_t&>(pReturnAddress)); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the return address from Tls"); \
            WEX_ASSERT(pReturnAddress, L"Failed to retrieve the return address from Tls"); \
            \
            /* Enter the critical section */ \
            ReadCriticalSectionLock globalLock(Detour::GetGlobalCriticalSection()); \
            \
            /* Only interact with the pDetour pointer if it's still valid; it could have gone out of scope before we were able to enter the critical section */ \
            if (DetourManager<TR CC (BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)), TDetourFunction>::IsValid(pTarget, pDetour)) \
            { \
                if (!Detour::IsDisabled()) \
                { \
                    /* The DetourIndex class will restore the per-detour/per-thread index within its destructor */ \
                    DetourIndex index(pDetour); \
                    if (SUCCEEDED(index.m_status)) \
                    { \
                        /* Iterate over the functions and invoke the first one found whose filter matches */ \
                        for (void* pRawDetourFunction = pDetour->GetDetour(index.Next()); pRawDetourFunction != NULL; pRawDetourFunction = pDetour->GetDetour(index.Next())) \
                        { \
                            /* If the index class encountered an error, bail out and just invoke the actual target function */ \
                            if (FAILED(index.m_status)) \
                            { \
                                break; \
                            } \
                            \
                            /* If the filter matches, invoke the function */ \
                            TDetourFunction* pDetourFunction = reinterpret_cast<TDetourFunction*>(pRawDetourFunction); \
                            if (pDetourFunction->FilterMatches(pReturnAddress BUILD_VARIABLE_NAME(DETOUR_FILTER_ARGS_, PARAMCOUNT))) \
                            { \
                                return pDetourFunction->Function(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
                            } \
                        } \
                    } \
                } \
                \
                /* If no match was found, invoke the target function instead */ \
                return (*reinterpret_cast<TargetFunction>(pDetour->GetTarget()))(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
            } \
            \
            /* If the detour was no longer valid, invoke the *real* target function instead */ \
            return (*pTarget)(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
        } \
        \
        static void* ShimPointer() \
        { \
            return &Shim; \
        } \
        \
        static void* ClassPointer() \
        { \
            return NULL; \
        } \
    }

    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_0 template <typename TR, typename TC, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_1 template <typename TR, typename TC, typename T1, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_2 template <typename TR, typename TC, typename T1, typename T2, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_3 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_4 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_5 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_6 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_7 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_8 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_9 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_10 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_11 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_12 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_13 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_14 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_15 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_16 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_17 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_18 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_19 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename T19, typename TDetourFunction>
    #define SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_20 template <typename TR, typename TC, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15, typename T16, typename T17, typename T18, typename T19, typename T20, typename TDetourFunction>

    #define DETOUR_METHOD_SHIM_IMPL(PARAMCOUNT, CC, IS_CONST) \
    BUILD_VARIABLE_NAME(SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_, PARAMCOUNT) \
    struct DetourShim<TR (CC TC::*)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)) BUILD_VARIABLE_NAME(MEMBER_PARAMETER_TYPES_CONST_, IS_CONST), TDetourFunction> \
    { \
        __declspec(noinline) TR CC Shim(BUILD_VARIABLE_NAME(DETOUR_SHIM_NAMED_ARGS_, PARAMCOUNT)) \
        { \
            /* Get the Target class pointer from Tls */ \
            TC* pThis = BUILD_VARIABLE_NAME(PinThis, CC)(reinterpret_cast<void*>(this)); \
            \
            /* Get the Detour instance from Tls */ \
            Detour* pDetour = NULL; \
            HRESULT hr = DetourThunk::GetDetourTlsValue(reinterpret_cast<intptr_t&>(pDetour)); \
            DBG_UNREFERENCED_LOCAL_VARIABLE(hr); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the Detour* pointer from Tls"); \
            WEX_ASSERT(pDetour, L"Failed to retrieve a valid Detour* pointer from Tls"); \
            \
            /* Get the Target function pointer from Tls */ \
            typedef TR (CC TC::*TargetFunction)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)) BUILD_VARIABLE_NAME(MEMBER_PARAMETER_TYPES_CONST_, IS_CONST); \
            TargetFunction pTarget = NULL; \
            hr = DetourThunk::GetTargetTlsValue(reinterpret_cast<intptr_t&>(pTarget)); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the target function pointer from Tls"); \
            WEX_ASSERT(pTarget, L"Failed to retrieve a valid target function pointer from Tls"); \
            \
            void* pReturnAddress = NULL; \
            hr = DetourThunk::GetReturnAddressTlsValue(reinterpret_cast<intptr_t&>(pReturnAddress)); \
            \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the return address from Tls"); \
            WEX_ASSERT(pReturnAddress, L"Failed to retrieve the return address from Tls"); \
            \
            /* Enter the critical section */ \
            ReadCriticalSectionLock globalLock(Detour::GetGlobalCriticalSection()); \
            \
            /* Only interact with the pDetour pointer if it's still valid; it could have gone out of scope before we were able to enter the critical section */ \
            if (DetourManager<TargetFunction, TDetourFunction>::IsValid(MemberAsPointerToPointer<TargetFunction>::Result(pTarget), pDetour)) \
            { \
                if (!Detour::IsDisabled()) \
                { \
                    /* The DetourIndex class will restore the per-detour/per-thread index within its destructor */ \
                    DetourIndex index(pDetour); \
                    if (SUCCEEDED(index.m_status)) \
                    { \
                        /* Iterate over the functions and invoke the first one found whose filter matches */ \
                        for (void* pRawDetourFunction = pDetour->GetDetour(index.Next()); pRawDetourFunction != NULL; pRawDetourFunction = pDetour->GetDetour(index.Next())) \
                        { \
                            /* If the index class encountered an error, bail out and just invoke the actual target function */ \
                            if (FAILED(index.m_status)) \
                            { \
                                break; \
                            } \
                            \
                            /* If the filter matches, invoke the function */ \
                            TDetourFunction* pDetourFunction = reinterpret_cast<TDetourFunction*>(pRawDetourFunction); \
                            if (pDetourFunction->FilterMatches(pReturnAddress BUILD_VARIABLE_NAME(DETOUR_METHOD_ARGS_, PARAMCOUNT))) \
                            { \
                                pThis = reinterpret_cast<TC*>(reinterpret_cast<unsigned __int64>(pThis) + pDetourFunction->GetThisAdjust()); \
                                return pDetourFunction->Function(*pThis BUILD_VARIABLE_NAME(DETOUR_METHOD_ARGS_, PARAMCOUNT)); \
                            } \
                        } \
                    } \
                } \
                \
                /* If no match was found, invoke the target function instead. */ \
                /* I haven't been able to find a safe/proper way to invoke pDetour->GetTarget() for virtual methods /* \
                /* So we can only safely call the target function with the original (detoured) function pointer -- which means we need need to temporarily disable the detour (this shim) /* \
                /* This causes the call to jump straight to the trampoline, bypassing this shim altogether. */ \
                AutoDisableDetour disableDetour(pDetour); \
                return (reinterpret_cast<TC*>(pThis)->*pTarget)(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
            } \
            \
            /* If the detour was no longer valid, that means the detour is no longer in place. /* \
            /* So it's safe to invoke the true target through its original function pointer */ \
            return (reinterpret_cast<TC*>(pThis)->*pTarget)(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
        } \
        \
        __declspec(noinline) static void* ShimPointer() \
        { \
            TR (CC DetourShim<TR (CC TC::*)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)) BUILD_VARIABLE_NAME(MEMBER_PARAMETER_TYPES_CONST_, IS_CONST), TDetourFunction>::*pShim)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)) = &Shim; \
            return (void*&)pShim; \
        } \
        \
        __declspec(noinline) TC* PinThis__stdcall(void* pThis) \
        { \
            /* For __stdcall, the this pointer is on the stack so it's less likely to be stomped during optimization */ \
            /* So hopefully this is enough to pin the pointer in __stdcall functions */ \
            return reinterpret_cast<TC*>(pThis); \
        } \
        \
        __declspec(noinline) TC* PinThis__thiscall(void*) \
        { \
            TC* pThis = NULL; \
            HRESULT hr = DetourThunk::GetTargetClassTlsValue(reinterpret_cast<intptr_t&>(pThis)); \
            WEX_ASSERT(SUCCEEDED(hr), L"Failed to retrieve the target class pointer from Tls"); \
            DBG_UNREFERENCED_LOCAL_VARIABLE(hr); \
            WEX_ASSERT(pThis, L"Failed to retrieve a valid target class pointer from Tls"); \
            return pThis; \
        } \
        \
        __declspec(noinline) static void* ClassPointer() \
        { \
            return &s_tc; \
        } \
        \
        static TC* s_tc; \
    }; \
    \
    BUILD_VARIABLE_NAME(SHIM_MEMBER_PARAMETER_TYPES_TEMPLATE_, PARAMCOUNT) \
    TC* DetourShim<TR (CC TC::*)(BUILD_VARIABLE_NAME(PARAMETER_TYPES_ARGS_, PARAMCOUNT)) BUILD_VARIABLE_NAME(MEMBER_PARAMETER_TYPES_CONST_, IS_CONST), TDetourFunction>::s_tc;

    #define DETOUR_METHOD_SHIM(PARAMCOUNT, CC)         \
        DETOUR_METHOD_SHIM_IMPL(PARAMCOUNT, CC, true); \
        DETOUR_METHOD_SHIM_IMPL(PARAMCOUNT, CC, false);

    #if defined(_M_IX86)
        DETOUR_SHIM(0, __stdcall);
        DETOUR_SHIM(1, __stdcall);
        DETOUR_SHIM(2, __stdcall);
        DETOUR_SHIM(3, __stdcall);
        DETOUR_SHIM(4, __stdcall);
        DETOUR_SHIM(5, __stdcall);
        DETOUR_SHIM(6, __stdcall);
        DETOUR_SHIM(7, __stdcall);
        DETOUR_SHIM(8, __stdcall);
        DETOUR_SHIM(9, __stdcall);
        DETOUR_SHIM(10, __stdcall);
        DETOUR_SHIM(11, __stdcall);
        DETOUR_SHIM(12, __stdcall);
        DETOUR_SHIM(13, __stdcall);
        DETOUR_SHIM(14, __stdcall);
        DETOUR_SHIM(15, __stdcall);
        DETOUR_SHIM(16, __stdcall);
        DETOUR_SHIM(17, __stdcall);
        DETOUR_SHIM(18, __stdcall);
        DETOUR_SHIM(19, __stdcall);
        DETOUR_SHIM(20, __stdcall);

        DETOUR_SHIM(0, __cdecl);
        DETOUR_SHIM(1, __cdecl);
        DETOUR_SHIM(2, __cdecl);
        DETOUR_SHIM(3, __cdecl);
        DETOUR_SHIM(4, __cdecl);
        DETOUR_SHIM(5, __cdecl);
        DETOUR_SHIM(6, __cdecl);
        DETOUR_SHIM(7, __cdecl);
        DETOUR_SHIM(8, __cdecl);
        DETOUR_SHIM(9, __cdecl);
        DETOUR_SHIM(10, __cdecl);
        DETOUR_SHIM(11, __cdecl);
        DETOUR_SHIM(12, __cdecl);
        DETOUR_SHIM(13, __cdecl);
        DETOUR_SHIM(14, __cdecl);
        DETOUR_SHIM(15, __cdecl);
        DETOUR_SHIM(16, __cdecl);
        DETOUR_SHIM(17, __cdecl);
        DETOUR_SHIM(18, __cdecl);
        DETOUR_SHIM(19, __cdecl);
        DETOUR_SHIM(20, __cdecl);

    #if !defined _MANAGED
        DETOUR_SHIM(0, __fastcall);
        DETOUR_SHIM(1, __fastcall);
        DETOUR_SHIM(2, __fastcall);
        DETOUR_SHIM(3, __fastcall);
        DETOUR_SHIM(4, __fastcall);
        DETOUR_SHIM(5, __fastcall);
        DETOUR_SHIM(6, __fastcall);
        DETOUR_SHIM(7, __fastcall);
        DETOUR_SHIM(8, __fastcall);
        DETOUR_SHIM(9, __fastcall);
        DETOUR_SHIM(10, __fastcall);
        DETOUR_SHIM(11, __fastcall);
        DETOUR_SHIM(12, __fastcall);
        DETOUR_SHIM(13, __fastcall);
        DETOUR_SHIM(14, __fastcall);
        DETOUR_SHIM(15, __fastcall);
        DETOUR_SHIM(16, __fastcall);
        DETOUR_SHIM(17, __fastcall);
        DETOUR_SHIM(18, __fastcall);
        DETOUR_SHIM(19, __fastcall);
        DETOUR_SHIM(20, __fastcall);
    #endif

        DETOUR_METHOD_SHIM(0, __thiscall);
        DETOUR_METHOD_SHIM(1, __thiscall);
        DETOUR_METHOD_SHIM(2, __thiscall);
        DETOUR_METHOD_SHIM(3, __thiscall);
        DETOUR_METHOD_SHIM(4, __thiscall);
        DETOUR_METHOD_SHIM(5, __thiscall);
        DETOUR_METHOD_SHIM(6, __thiscall);
        DETOUR_METHOD_SHIM(7, __thiscall);
        DETOUR_METHOD_SHIM(8, __thiscall);
        DETOUR_METHOD_SHIM(9, __thiscall);
        DETOUR_METHOD_SHIM(10, __thiscall);
        DETOUR_METHOD_SHIM(11, __thiscall);
        DETOUR_METHOD_SHIM(12, __thiscall);
        DETOUR_METHOD_SHIM(13, __thiscall);
        DETOUR_METHOD_SHIM(14, __thiscall);
        DETOUR_METHOD_SHIM(15, __thiscall);
        DETOUR_METHOD_SHIM(16, __thiscall);
        DETOUR_METHOD_SHIM(17, __thiscall);
        DETOUR_METHOD_SHIM(18, __thiscall);
        DETOUR_METHOD_SHIM(19, __thiscall);
        DETOUR_METHOD_SHIM(20, __thiscall);

        DETOUR_METHOD_SHIM(0, __stdcall);
        DETOUR_METHOD_SHIM(1, __stdcall);
        DETOUR_METHOD_SHIM(2, __stdcall);
        DETOUR_METHOD_SHIM(3, __stdcall);
        DETOUR_METHOD_SHIM(4, __stdcall);
        DETOUR_METHOD_SHIM(5, __stdcall);
        DETOUR_METHOD_SHIM(6, __stdcall);
        DETOUR_METHOD_SHIM(7, __stdcall);
        DETOUR_METHOD_SHIM(8, __stdcall);
        DETOUR_METHOD_SHIM(9, __stdcall);
        DETOUR_METHOD_SHIM(10, __stdcall);
        DETOUR_METHOD_SHIM(11, __stdcall);
        DETOUR_METHOD_SHIM(12, __stdcall);
        DETOUR_METHOD_SHIM(13, __stdcall);
        DETOUR_METHOD_SHIM(14, __stdcall);
        DETOUR_METHOD_SHIM(15, __stdcall);
        DETOUR_METHOD_SHIM(16, __stdcall);
        DETOUR_METHOD_SHIM(17, __stdcall);
        DETOUR_METHOD_SHIM(18, __stdcall);
        DETOUR_METHOD_SHIM(19, __stdcall);
        DETOUR_METHOD_SHIM(20, __stdcall);
    #else
        DETOUR_SHIM(0, __stdcall);
        DETOUR_SHIM(1, __stdcall);
        DETOUR_SHIM(2, __stdcall);
        DETOUR_SHIM(3, __stdcall);
        DETOUR_SHIM(4, __stdcall);
        DETOUR_SHIM(5, __stdcall);
        DETOUR_SHIM(6, __stdcall);
        DETOUR_SHIM(7, __stdcall);
        DETOUR_SHIM(8, __stdcall);
        DETOUR_SHIM(9, __stdcall);
        DETOUR_SHIM(10, __stdcall);
        DETOUR_SHIM(11, __stdcall);
        DETOUR_SHIM(12, __stdcall);
        DETOUR_SHIM(13, __stdcall);
        DETOUR_SHIM(14, __stdcall);
        DETOUR_SHIM(15, __stdcall);
        DETOUR_SHIM(16, __stdcall);
        DETOUR_SHIM(17, __stdcall);
        DETOUR_SHIM(18, __stdcall);
        DETOUR_SHIM(19, __stdcall);
        DETOUR_SHIM(20, __stdcall);

        DETOUR_METHOD_SHIM(0, __thiscall);
        DETOUR_METHOD_SHIM(1, __thiscall);
        DETOUR_METHOD_SHIM(2, __thiscall);
        DETOUR_METHOD_SHIM(3, __thiscall);
        DETOUR_METHOD_SHIM(4, __thiscall);
        DETOUR_METHOD_SHIM(5, __thiscall);
        DETOUR_METHOD_SHIM(6, __thiscall);
        DETOUR_METHOD_SHIM(7, __thiscall);
        DETOUR_METHOD_SHIM(8, __thiscall);
        DETOUR_METHOD_SHIM(9, __thiscall);
        DETOUR_METHOD_SHIM(10, __thiscall);
        DETOUR_METHOD_SHIM(11, __thiscall);
        DETOUR_METHOD_SHIM(12, __thiscall);
        DETOUR_METHOD_SHIM(13, __thiscall);
        DETOUR_METHOD_SHIM(14, __thiscall);
        DETOUR_METHOD_SHIM(15, __thiscall);
        DETOUR_METHOD_SHIM(16, __thiscall);
        DETOUR_METHOD_SHIM(17, __thiscall);
        DETOUR_METHOD_SHIM(18, __thiscall);
        DETOUR_METHOD_SHIM(19, __thiscall);
        DETOUR_METHOD_SHIM(20, __thiscall);
    #endif
} /* namespace Private */ } /* namespace Mock10 */

#pragma pop_macro("Assert")